home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
edit
/
xvisrc.zip
/
SCREEN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-28
|
33KB
|
1,420 lines
/* Copyright (c) 1990,1991,1992 Chris and John Downey */
#ifndef lint
static char *sccsid = "@(#)screen.c 2.3 (Chris & John Downey) 9/4/92";
#endif
/***
* program name:
xvi
* function:
PD version of UNIX "vi" editor, with extensions.
* module name:
screen.c
* module function:
Screen handling functions.
* history:
STEVIE - ST Editor for VI Enthusiasts, Version 3.10
Originally by Tim Thompson (twitch!tjt)
Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
Heavily modified by Chris & John Downey
***/
#include "xvi.h"
/*
* Size of command buffer - we won't allow anything more
* to be typed when we get to this limit.
*/
#define CMDSZ 80
/*
* The following is used to optimise screen updating; we
* keep a record of the real screen state and compare it
* with the new version before actually doing any updating.
*
* The l_line part is guaranteed to be always null-terminated.
*/
typedef struct line_struct {
char *l_line; /* storage for characters in line */
int l_used; /* number of bytes actually used */
unsigned int l_flags; /* information bits */
} Sline;
/*
* Bit definitions for l_flags.
*/
#define L_TEXT 0x01 /* is an ordinary text line */
#define L_MARKER 0x02 /* is a marker line ('@' or '~') */
#define L_DIRTY 0x04 /* has been modified */
#define L_MESSAGE 0x08 /* is a message line */
#define L_COMMAND 0x10 /* is a command line */
#define L_READONLY 0x20 /* message line for readonly buffer */
#define L_STATUS (L_MESSAGE | L_COMMAND) /* is a status line */
static Sline *new_screen; /* screen being updated */
static Sline *real_screen; /* state of real screen */
/*
* Status line glitch handling.
*
* Some terminals leave a space when changing colour. The number of spaces
* left is returned by the v_colour_cost() method within the VirtScr, and
* stored in the colour_cost variable herein - this is not perfect, it should
* really be in the Xviwin structure, but what the hell.
*
* "st_spare_cols" is the number of columns which are not used at the
* end of the status line; this is to prevent wrapping on this line,
* as this can do strange things to some terminals.
*/
static int colour_cost = 0;
static int st_spare_cols = 1;
static int line_to_new P((Xviwin *, Line *, int, long));
static void file_to_new P((Xviwin *));
static void new_to_screen P((VirtScr *, int, int));
static void do_sline P((Xviwin *));
static void clrline P((int));
/*
* This routine must be called to set up the screen memory -
* if it is not, we will probably get a core dump.
*
* Note that, at the moment, it must be called with a whole-screen
* window, i.e. the first window, and only that window, so that the
* nrows and ncols fields represent the whole screen.
*/
/*ARGSUSED*/
void
init_screen(win)
Xviwin *win;
{
static char *real_area, *new_area;
register int count;
VirtScr *vs;
vs = win->w_vs;
colour_cost = VScolour_cost(vs);
st_spare_cols = 1 + (colour_cost * 2);
/*
* If we're changing the size of the screen, free the old stuff.
*/
if (real_screen != NULL) {
free((char *) real_screen);
free((char *) new_screen);
free(real_area);
free(new_area);
}
/*
* Allocate space for the lines, and for the structure holding
* information about each line. Notice that we allocate an
* extra byte at the end of each line for null termination.
*/
real_screen = (Sline *) malloc((unsigned) VSrows(vs) * sizeof(Sline));
new_screen = (Sline *) malloc((unsigned) VSrows(vs) * sizeof(Sline));
real_area = malloc((unsigned) VSrows(vs) * (VScols(vs) + 1));
new_area = malloc((unsigned) VSrows(vs) * (VScols(vs) + 1));
if (real_screen == NULL || new_screen == NULL ||
real_area == NULL || new_area == NULL) {
/* What to do now? */
sys_exit(0);
}
/*
* Now assign all the rows ...
*/
for (count = 0; count < VSrows(vs); count++) {
register Sline *rp, *np;
register int offset;
rp = &real_screen[count];
np = &new_screen[count];
offset = count * (VScols(vs) + 1);
rp->l_line = real_area + offset;
np->l_line = new_area + offset;
rp->l_line[0] = np->l_line[0] = '\0';
rp->l_used = np->l_used = 0;
rp->l_flags = np->l_flags = 0;
}
}
/*
* Set the L_DIRTY bit for a given line in both real_screen &
* new_screen if the stored representations are in fact different:
* otherwise clear it.
*/
static void
mark_dirty(row)
int row;
{
Sline *rp;
Sline *np;
int used;
rp = &real_screen[row];
np = &new_screen[row];
if (
(rp->l_flags & ~L_DIRTY) != (np->l_flags & ~L_DIRTY)
||
(used = rp->l_used) != np->l_used
||
strncmp(rp->l_line, np->l_line, used) != 0
) {
/*
* The lines are different.
*/
np->l_flags |= L_DIRTY;
rp->l_flags |= L_DIRTY;
} else {
rp->l_flags = (np->l_flags &= ~L_DIRTY);
}
}
/*
* Transfer the specified window line into the "new" screen array, at
* the given row. Returns the number of screen lines taken up by the
* logical buffer line lp, or 0 if the line would not fit; this happens
* with longlines at the end of the screen. In this case, the lines
* which could not be displayed will have been marked with an '@'.
*/
static int
line_to_new(window, lp, start_row, line)
Xviwin *window;
Line *lp;
int start_row;
long line;
{
register unsigned c; /* next character from file */
register Sline *curr_line; /* output line - used for efficiency */
register char *ltext; /* pointer to text of line */
register int curr_index; /* current index in line */
bool_t eoln; /* true when line is done */
char extra[MAX_TABSTOP];
/* Stack for extra characters. */
int nextra = 0; /* index into stack */
int srow, scol; /* current screen row and column */
int vcol; /* virtual column */
ltext = lp->l_text;
srow = start_row;
scol = vcol = 0;
curr_line = &new_screen[srow];
curr_index = 0;
eoln = FALSE;
if (Pb(P_number)) {
static Flexbuf ftmp;
flexclear(&ftmp);
(void) lformat(&ftmp, NUM_FMT, line);
(void) strcpy(curr_line->l_line, flexgetstr(&ftmp));
scol += NUM_SIZE;
}
while (!eoln) {
/*
* Get the next character to put on the screen.
*/
/*
* "extra" is a stack containing any extra characters
* we have to put on the screen - this is for chars
* which have a multi-character representation, and
* for the $ at end-of-line in list mode.
*/
if (nextra > 0) {
c = extra[--nextra];
} else {
unsigned n;
c = (unsigned char) (ltext[curr_index++]);
/*
* Deal with situations where it is not
* appropriate just to copy characters
* straight onto the screen.
*/
if (c == '\0') {
if (Pb(P_list)) {
/*
* Have to show a '$' sign in list mode.
*/
extra[nextra++] = '\0';
c = '$';
}
} else {
char *p;
n = vischar((int) c, &p, vcol);
/*
* This is a bit paranoid assuming
* that Pn(P_tabstop) can never be
* greater than sizeof (extra), but
* so what.
*/
if (nextra + n > sizeof extra)
n = (sizeof extra - nextra);
/*
* Stack the extra characters so that
* they appear in the right order.
*/
while (n > 1) {
extra[nextra++] = p[--n];
}
c = p[0];
}
}
if (c == '\0') {
/*
* End of line. Terminate it and finish.
*/
eoln = TRUE;
curr_line->l_flags = L_TEXT;
curr_line->l_used = scol;
curr_line->l_line[scol] = '\0';
mark_dirty(srow);
break;
} else {
/*
* Sline folding.
*/
if (scol >= window->w_ncols) {
curr_line->l_flags = L_TEXT;
curr_line->l_used = scol;
curr_line->l_line[scol] = '\0';
mark_dirty(srow);
srow += 1;
scol = 0;
curr_line = &new_screen[srow];
}
if (srow >= window->w_cmdline) {
for (srow = start_row; srow < window->w_cmdline; srow++) {
curr_line = &new_screen[srow];
curr_line->l_flags = L_MARKER;
curr_line->l_used = 1;
curr_line->l_line[0] = '@';
curr_line->l_line[1] = '\0';
mark_dirty(srow);
}
return(0);
}
/*
* Store the character in new_scree